package pri.zxx.excelgenerate.excelhanler;

import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.springframework.core.io.ClassPathResource;
import pri.zxx.excelgenerate.dataentity.entity.CreatRequest;
import pri.zxx.excelgenerate.dataentity.tabledata.CellData;
import pri.zxx.excelgenerate.excelhanler.excelentity.CustomCell;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
public class ExcelUtil {


    /**
     * @param max      最大单元格数量 当标题为true时，最大列将+2  例如 max=4 ，生成的范围将占用6列
     * @param mult     生成多少个范围
     * @param hasTitle 是否有标题， 标题默认占用2 格
     * @return 一行中单元格配比数据
     */
    public static List<CustomCell> genarateCellsByRange(int max, boolean hasTitle, int mult) {
        //需要生成的cell数量
        if (mult > max) {
            throw new RuntimeException("");
        }
        List<CustomCell> cells = new ArrayList<>(mult);

        //先平分
        int i = max / mult;
        //再分余数
        int i1 = max % mult;
        //[0,0,0,0] 存储每个单元格占用的格子数量
        Integer[] range = new Integer[mult];
        Arrays.fill(range, i);
        for (int j = 0; j < i1; j++) {
            range[j] = range[j] + 1;
        }

        log.debug("单元格规格：{}", Arrays.toString(range));


        int start = 0;//开始标号为2
        if (hasTitle) {
            cells.add(new CustomCell("", 0, 1));//标题占用2格
            start = 2;
        }
        int end;
        for (Integer count : range) {
            end = start + count - 1;
            cells.add(new CustomCell("", start, end));
            start = end + 1;
        }
        return cells;
    }


    /**
     * 设置自适应行高的方法
     */
    public static int computeHeight(HSSFCellStyle cellStyle, HSSFWorkbook workbook, String content) {
        //1.先取出内容 计算长度 （这个方法在后面...）
//        String content = getCellContent(cell);
        log.debug("-->>开始计算高度的内容：{}", content);
        //计算字体的高度
        HSSFFont font = cellStyle.getFont(workbook);
        //字体的高度
        short fontHeightInPoints = font.getFontHeightInPoints();
        log.debug("字体高度，{}", fontHeightInPoints);
        //计算字符的宽度
        //代入默认字符宽度8：//字符像素宽度 = 字体宽度 * 字符个数 + 边距
        //像素 = 5 + (字符个数 * 7)
//        int i = 5 + (content.toCharArray().length * 7);
        //POI中的字符宽度算法是：double 宽度 = (字符个数 * (字符宽度 - 1) + 5) / (字符宽度 - 1) * 256;
        double poiWidth = (float) content.length() * 12 / 7 * 256;
        //然后再四舍五入成整数。
        int width = (int) Math.ceil(poiWidth);
        log.debug("文本内容宽度：{}", width);
        //2.除以宽度 计算行数乘以行高   (256*80) 是我设置的我的单元格列的宽度
        double rowNum = (double) width / (256 * 80);
        log.debug("行数：{}", rowNum);
        int rowNums = (int) Math.ceil(rowNum);
        int i1 = rowNums == 0 ? 1 : rowNums;
        int i = i1 * (3 + fontHeightInPoints);//直接设置行高为这个值就OK了
        log.debug("-->>结束 行高：{}", i);
        return i;
    }

    /**
     * 合并单元格的border
     */
    public static void handleRangeBorder(RangeBorder rb) {
        CellRangeAddress region = rb.getRegion();
        HSSFSheet sheet = rb.getSheet();
        RegionUtil.setBorderTop(rb.t, region, sheet);
        RegionUtil.setBorderRight(rb.r, region, sheet);
        RegionUtil.setBorderLeft(rb.l, region, sheet);
        RegionUtil.setBorderBottom(rb.b, region, sheet);
        sheet.addMergedRegion(region);
    }


    @Data
    @Accessors(chain = true)
    @Builder
    public static class RangeBorder {
        private BorderStyle l;
        private BorderStyle t;
        private BorderStyle r;
        private BorderStyle b;
        private HSSFSheet sheet;
        private CellRangeAddress region;
    }

    public static Boolean isWeight(CreatRequest cr) {
	    return switch (cr.getPredictionTypeEnum()) {
		    case GROWING_FINISHING -> true;
		    case STARTING_PIGS -> null;
		    default -> false;
	    };
    }

    /**
     * 获取数据实体中表格定义信息
     */
    public static Map<String, List<CellData>> getTableDefinition(Class<?> tClass) {
        List<CellData> cellData = new ArrayList<>();
        Field[] declaredFields = tClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            CellDesc declaredAnnotation = declaredField.getDeclaredAnnotation(CellDesc.class);
            if (declaredAnnotation != null) {
                cellData.add(new CellData(declaredAnnotation.titleName(), declaredAnnotation.order(), declaredField, declaredAnnotation.position()));
            }
        }
        return cellData.stream().collect(Collectors.groupingBy(CellData::getTitleName));
    }


    /**
     * 插入图片
     */
    public static void insertPic(HSSFWorkbook workbook, HSSFSheet sheet, String picPath) {
        try {
            //获得画图的管理类
            ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
            //anchor主要用于设置图片的属性
            HSSFPatriarch drawingPatriarch = sheet.createDrawingPatriarch();
            HSSFClientAnchor anchor = drawingPatriarch.createAnchor(50, 75, 20, 20, 0, 0, 1, 1);
            anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);

            if (StringUtils.isNotEmpty(picPath)) {
                ClassPathResource pathResource = new ClassPathResource(picPath);
                //将图片读到BufferedImage
                BufferedImage bufferedImage = ImageIO.read(pathResource.getInputStream());
                // 将图片写入流中
                ImageIO.write(bufferedImage, "png", byteArrayOut);
                HSSFPicture picture = drawingPatriarch.createPicture(anchor, workbook.addPicture(byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_PNG));
                picture.resize(1.2, 0.7);
                log.info("添加图片完成 地址:{}", picPath);
            }
        } catch (Exception e) {
            log.error("添加图片到excel中异常", e);
        }
    }


    public static void addPdfMark(String pdfPath, String waterPath, String logoPath, String outPath) throws Exception {

        PdfReader reader = new PdfReader(pdfPath, "PDF".getBytes());
        // 如果是web项目，直接下载应该放到response的流里面
        // PdfStamper stamp = new PdfStamper(reader,response.getOutputStream());
        // 添加水印之后的pdf文件
        PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(outPath));
        int pageSize = reader.getNumberOfPages();
        float pageHeight = reader.getPageSize(1).getHeight();
        float pageWidth = reader.getPageSize(1).getWidth();
        try {
            ClassPathResource cpr = new ClassPathResource(waterPath);
            com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(IOUtils.toByteArray(cpr.getInputStream()));
            ClassPathResource lg = new ClassPathResource(logoPath);
            com.itextpdf.text.Image logo = com.itextpdf.text.Image.getInstance(IOUtils.toByteArray(lg.getInputStream()));
            float width = img.getWidth();
            float height = img.getHeight();
            img.scaleAbsolute(width * 0.5f, height * 0.5f);

            float logoWidth = logo.getWidth();
            float logoHeight = logo.getHeight();
            logo.scaleAbsolute(logoWidth * 0.5f, logoHeight * 0.4f);

            // 每两行显示两个 左边一个，右边一个
            int lineNum = (int) (pageHeight / height); // 行数
            for (int i = 1; i <= pageSize; i++) {
                PdfContentByte under = stamp.getUnderContent(i);
                for (int j = 0; j < lineNum; j = j + 3) {
                    PdfContentByte underWater = stamp.getUnderContent(i);
                    // 放入水印
                    // 将水印显示到最底层
                    img.setAlignment(com.itextpdf.text.Image.UNDERLYING);
                    // 水印的位置
                    img.setAbsolutePosition(pageWidth * RandomUtils.insecure().randomFloat(0.1f, 0.8f), (j+1) * height);
                    // 旋转 角度
                    img.setRotationDegrees(RandomUtils.insecure().randomInt(0, 90));

                    PdfGState gs = new PdfGState();
                    // 设置透明度为0.5
                    gs.setFillOpacity(0.4f);
                    underWater.setGState(gs);
                    underWater.addImage(img);
                }

                logo.setAbsolutePosition(30, pageHeight - logoHeight);
                logo.setAlignment(com.itextpdf.text.Image.UNDERLYING);
                logo.setRotationDegrees(0);
                PdfGState gs = new PdfGState();
                // 设置透明度为0.5
                gs.setFillOpacity(1f);
                under.setGState(gs);
                under.addImage(logo);

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            stamp.close();
            reader.close();
        }
    }
}
